package com.longway.common.token.utils;

import com.alibaba.fastjson.JSON;
import com.longway.common.token.entity.TokenHeader;
import com.longway.common.token.entity.TokenPlayload;
import com.jfinal.kit.Base64Kit;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.Ret;

import java.util.UUID;

/**
 * Description:Token生成工具
 * 第一部分我们称它为头部（header),第二部分我们称其为载荷（payload, 类似于飞机上承载的物品)，第三部分是签证（signature).
 */
public class TokenUtil {
    public static final  String TOKEN_AES_KEY = "cnjcsoftToken";
    public static final  String REFREH_TOKEN_AES_KEY = "cnjcsoftRefreshToken";
    public static final  String JWT_TYP = "JWT";
    public static final  String JWT_ALG = "AES";
    public static final  String JWT_EXP = "120";
    public static final  String JWT_ISS = "cnjcsoft";
    public static final  String TOKEN_HEADER = "TokenHeader";
    public static final  String TOKEN_PAYLOAD = "TokenPlayload";
    /**
     * 获得token
     * @param data 自定义数据
     * @param <T> 自定义数据
     * @return
     * @throws Exception
     */
    public static <T> String getToken(T data) throws Exception {
        TokenPlayload<T> userTokenPlayload = new TokenPlayload<>();
        userTokenPlayload.setExpData(data);
        String jwt = createJWT(userTokenPlayload);
        return jwt;
    }

    /**
     * 生成jwt的header部分内容
     * @return
     * @throws Exception
     */
    private static String tokenHeaderBase64() throws Exception {
        TokenHeader tokenHeader = new TokenHeader();
        tokenHeader.setTyp(JWT_TYP);
        tokenHeader.setAlg(JWT_ALG);
        String headerJson = JsonKit.toJson(tokenHeader);
        String headerBase64 = Base64Kit.encode(headerJson.getBytes());
        return headerBase64;
    }

    /**
     * 生成jwt的payload部分内容
     * @param tokenPlayload
     * @param <T>自定义的数据块
     * @return
     * @throws Exception
     */
    private static <T> String tokenPayloadBase64(TokenPlayload<T> tokenPlayload) throws Exception {
        tokenPlayload.setIss(JWT_ISS);
        tokenPlayload.setExp(JWT_EXP);

        tokenPlayload.setIat(String.valueOf(System.currentTimeMillis()));

        String tokenPlayloadJson = JsonKit.toJson(tokenPlayload);

        String tokenPlayloadBase64 = Base64Kit.encode(tokenPlayloadJson.getBytes());

        return tokenPlayloadBase64;
    }

    /**
     * 生成JWT
     * @return
     */
    public static <T> String createJWT(TokenPlayload<T> tokenPlayload) throws Exception {
        StringBuilder jwtSb = new StringBuilder();
        StringBuilder headerPlayloadSb = new StringBuilder();

        String tokenHeaderBase64 = tokenHeaderBase64();
        String tokenPayloadBase64 = tokenPayloadBase64(tokenPlayload);

        jwtSb.append(tokenHeaderBase64);
        jwtSb.append(".");
        jwtSb.append(tokenPayloadBase64);
        jwtSb.append(".");

        headerPlayloadSb.append(tokenHeaderBase64);
        headerPlayloadSb.append(tokenPayloadBase64);

        String headerPlayloadSalt = SaltUtil.addSalt(headerPlayloadSb.toString());

        String key = AesUtil.initKey(TOKEN_AES_KEY+tokenPlayload.getIat());

        String  signature = Base64Kit.encode(AesUtil.encrypt(headerPlayloadSalt.getBytes(),key));

        jwtSb.append(signature);

        return Base64Kit.encode(jwtSb.toString().getBytes());
    }

    /**
     * 校验token是否是服务器生成的，以防token被修改
     * @param jwtBase64
     * @return
     * @throws Exception
     */
    public static <T> boolean verifyJWT(String jwtBase64) throws Exception {
        String jwt = new String (Base64Kit.decode(jwtBase64));

        if(!jwt.contains(".")){
            return false;
        }

        String[] jwts = jwt.split("\\.");
        if(jwts.length<3){
            return false;
        }

        TokenPlayload tTokenPlayload =  JSON.parseObject(new String(Base64Kit.decode(jwts[1])),TokenPlayload.class);
        String key = AesUtil.initKey(TOKEN_AES_KEY+tTokenPlayload.getIat());

        //解析出header跟playload
        StringBuilder headerPlayloadSb = new StringBuilder();
        headerPlayloadSb.append(jwts[0]);
        headerPlayloadSb.append(jwts[1]);

        //解析signature
        String  headerPlayloadSalt = new String (AesUtil.decrypt(Base64Kit.decode(jwts[2]),key));

        return SaltUtil.verifyPwd(headerPlayloadSb.toString(),headerPlayloadSalt);
    }
    
    public static <T> Ret parseData(String jwtBase64) throws Exception {
        String jwt = new String (Base64Kit.decode(jwtBase64));

        if(!jwt.contains(".")){
            return Ret.fail("msg", "无效token");
        }

        String[] jwts = jwt.split("\\.");
        if(jwts.length<3){
        	 return Ret.fail("msg", "无效token");
        }
        TokenPlayload tTokenPlayload =  JSON.parseObject(new String(Base64Kit.decode(jwts[1])),TokenPlayload.class);
        //验证是否过期
        //获取签发时间
        //Long iat = Long.parseLong(tTokenPlayload.getIat());
        //获取过期时间
        /*Long exp = Long.parseLong(tTokenPlayload.getExp());
        Long expTime = iat + exp * 60 * 1000;
        //过期时间小于当前时间,则有效,否则token过期
        if(System.currentTimeMillis() > expTime ){//说明已过期
        	return Ret.fail("msg", "无效token");
        }*/
        
        
        String key = AesUtil.initKey(TOKEN_AES_KEY+tTokenPlayload.getIat());
        
        //解析出header跟playload
        StringBuilder headerPlayloadSb = new StringBuilder();
        headerPlayloadSb.append(jwts[0]);
        headerPlayloadSb.append(jwts[1]);
        //解析signature
        String  headerPlayloadSalt = new String(AesUtil.decrypt(Base64Kit.decode(jwts[2]),key));
        boolean flag = SaltUtil.verifyPwd(headerPlayloadSb.toString(),headerPlayloadSalt);
        if(flag){
        	TokenHeader tTokenHeader =  JSON.parseObject(new String(Base64Kit.decode(jwts[0])),TokenHeader.class);
        	return Ret.ok().set(TOKEN_PAYLOAD, tTokenPlayload)
        			.set(TOKEN_HEADER, tTokenHeader);
        }
        
        return Ret.fail("msg", "无效token");
    }

    /**
     * 生成refreshToken
     * @return
     */
    public static String createRefreshToken(String jwt) throws Exception {
        StringBuilder seedSb = new StringBuilder();
        seedSb.append(TOKEN_AES_KEY).append(jwt).append(UUID.randomUUID());
        String key = AesUtil.initKey(seedSb.toString());
        System.out.println("密匙："+key);
        String  refreshToken = Base64Kit.encode(AesUtil.encrypt(jwt.getBytes(),key));
        return refreshToken;
    }
    

    public static void main(String[] args) throws Exception {
      /*  String jwt = getToken(new BaseUser().set("id", 111).set("account","aaa").set("status",2));
        System.out.println("jwt:"+jwt);*/
        System.out.println("verifyJWT:"+verifyJWT("ZXlKaGJHY2lPaUpCUlZNaUxDSjBlWEFpT2lKS1YxUWlmUT09LmV5SmxlSEFpT2lJek1DSXNJbVY0Y0VSaGRHRWlPbnNpWVdOamIzVnVkQ0k2SW1Ga2JXbHVJaXdpYVdRaU9qRXNJbk4wWVhSMWN5STZNaXdpYzNSaGRIVnpSR1ZzWlhSbElqcG1ZV3h6WlN3aWMzUmhkSFZ6VEc5amEwbGtJanBtWVd4elpTd2ljM1JoZEhWelQyc2lPblJ5ZFdVc0luTjBZWFIxYzFKbFpuVnpaU0k2Wm1Gc2MyVXNJbk4wWVhSMWMxSmxaeUk2Wm1Gc2MyVjlMQ0pwWVhRaU9pSXhOVFUxTmpjd09UZ3lOemMxSWl3aWFYTnpJam9pWTI1cVkzTnZablFpZlE9PS5zbERZb0RxNVZuUEh1R1N1dnhOTzlXRWo3eGdyeUMzM1pUTTM5dzZmMnZSMnlGODBFWGtwekY3VDFNREkrNFhKam9mTk1zMHNiUmVBRUpMYk1YaGRpZz09"));
    }
}
